Syntax10.Scn.Fnt FoldElems Syntax10.Scn.Fnt (* ---------------------------------------------------------- Backup does an incremental backup between two directories, i.e. only the files that have changed since the last backup are copied. Backup.WriteFiles ( {source destination} ~ | "^") Source and destination are given as Macintosh path names starting with the volume name and ending with ":". If a path name contains blanks it must be written under quotes. Example: Backup.WriteFiles Othello:Text:Lectures:EiP: hm:Backup:EiP: ~ ----------------------------------------------------------*) Syntax10i.Scn.Fnt StampElems Alloc 8 May 95 Syntax10.Scn.Fnt VAR i: INTEGER; BEGIN i := 0; WHILE in[i] # 0X DO out[i+1] := in[i]; INC(i) END; out[0] := CHR(i) END MakeStr255; Syntax10.Scn.Fnt VAR res: INTEGER; BEGIN NEW(par); par.ioCompletion := 0; par.ioNamePtr := SYSTEM.ADR(spec.name); par.ioVRefNum := spec.vRefNum; par.ioDirID := spec.parID; par.ioFDirIndex := 0; res := PBGetCatInfo(par); ASSERT(res = 0) END GetFileInfo; Syntax10.Scn.Fnt VAR res: INTEGER; BEGIN NEW(par); par.ioCompletion := 0; par.ioNamePtr := SYSTEM.ADR(spec.name); par.ioVRefNum := spec.vRefNum; par.ioDrDirID := spec.parID; par.ioFDirIndex := 0; res := PBGetCatInfo(par); ASSERT(res = 0) END GetDirInfo; Syntax10.Scn.Fnt VAR ch, start: CHAR; i: INTEGER; BEGIN REPEAT In.Char(ch) UNTIL (ch > " ") OR ~In.Done; i := 1; IF (ch = '"') OR (ch = "'") THEN start := ch; In.Char(ch); WHILE In.Done & (ch # start) DO s[i] := ch; INC(i); In.Char(ch) END; In.Char(ch); ELSE WHILE In.Done & (ch > " ") DO s[i] := ch; INC(i); In.Char(ch) END END; s[i] := 0X; s[0] := CHR(i-1) END ReadString; Syntax10.Scn.Fnt VAR i: INTEGER; BEGIN FOR i := 1 TO ORD(s[0]) DO Out.Char(s[i]) END END PrintString; Syntax10.Scn.Fnt VAR i: INTEGER; BEGIN IF a[0] # b[0] THEN RETURN FALSE END; i := ORD(a[0]); WHILE (i > 0) & (a[i] = b[i]) DO DEC(i) END; RETURN i = 0 END EqualString; Syntax10.Scn.Fnt VAR f: File; BEGIN NEW(f); f.next := NIL; f.spec := spec; f.date := info.ioFlMdDat; f.len := info.ioFlLgLen; f.rlen := info.ioFlRLgLen; f.creator := info.ioFlFndrInfo.fdCreator; f.type := info.ioFlFndrInfo.fdType; IF f.len > maxLen THEN maxLen := f.len END; IF f.rlen > maxLen THEN maxLen := f.rlen END; RETURN f END NewFile; Syntax10.Scn.Fnt VAR g: File; BEGIN g := d.files; WHILE (g # NIL) & ~EqualString(f.spec.name, g.spec.name) DO g := g.next END; RETURN g END ThisFile; Syntax10.Scn.Fnt FoldElems Syntax10.Scn.Fnt IF g # NIL THEN res := Sys.FSpDelete(g.spec); ASSERT(res = 0, 99) ELSE NEW(g); FOR i := 0 TO ORD(f.spec.name[0]) DO s[i] := f.spec.name[i] END; res := Sys.FSMakeFSSpec(dt.spec.vRefNum, dt.dirID, s, g.spec); ASSERT(res = fnfErr, 98) END; res := Sys.FSpCreate(g.spec, f.creator, f.type, Sys.smSystemScript); ASSERT(res = 0, 97); Syntax10i.Scn.Fnt Syntax10.Scn.Fnt res := Sys.FSpOpenDF(f.spec, 0, fRef); ASSERT(res = 0, 96); res := Sys.FSpOpenDF(g.spec, 0, gRef); ASSERT(res = 0, 95); res := Sys.FSRead(fRef, f.len, SYSTEM.ADR(buf^)); ASSERT(res = 0, 94); res := Sys.FSWrite(gRef, f.len, SYSTEM.ADR(buf^)); ASSERT(res = 0, 93); res := Sys.FSClose(fRef); ASSERT(res = 0, 92); res := Sys.FSClose(gRef); ASSERT(res = 0, 91); PrintString(f.spec.name); Syntax10.Scn.Fnt IF f.rlen > 0 THEN res := Sys.FSpOpenRF(f.spec, 0, fRef); ASSERT(res = 0, 90); res := Sys.FSpOpenRF(g.spec, 0, gRef); ASSERT(res = 0, 89); res := Sys.FSRead(fRef, f.rlen, SYSTEM.ADR(buf^)); ASSERT(res = 0, 88); res := Sys.FSWrite(gRef, f.rlen, SYSTEM.ADR(buf^)); ASSERT((res = 0) OR (res = -5000), 87); IF res = -5000 THEN Out.String(" (error -5000)") END; res := Sys.FSClose(fRef); ASSERT(res = 0, 86); res := Sys.FSClose(gRef); ASSERT(res = 0, 85); Out.String(" + resources") END; VAR res, i: INTEGER; s: Sys.Str255; fRef, gRef: INTEGER; info: FileInfo; BEGIN create empty g on dt copy data fork copy resource fork Out.String(" saved$"); INC(savedFiles) END SaveFile; Syntax10.Scn.Fnt VAR d: Directory; info: DirInfo; res: INTEGER; BEGIN NEW(d); d.next := NIL; d.files := NIL; d.dirs := NIL; d.spec := spec; GetDirInfo(spec, info); d.dirID := info.ioDrDirID; d.date := info.ioDrMdDat; RETURN d END NewDir; Syntax10.Scn.Fnt VAR spec: Sys.FSSpec; s: Sys.Str255; res, i: INTEGER; dummy: LONGINT; BEGIN FOR i := 0 TO ORD(df.spec.name[0]) DO s[i] := df.spec.name[i] END; res := Sys.FSMakeFSSpec(parent.spec.vRefNum, parent.dirID, s, spec); ASSERT(res = fnfErr, 29); res := Sys.FSpDirCreate(spec, Sys.smSystemScript, dummy); ASSERT(res = 0, 30); dt := NewDir(spec) END CreateDir; Syntax10.Scn.Fnt VAR g: File; BEGIN g := d.dirs; WHILE (g # NIL) & ~EqualString(f.spec.name, g.spec.name) DO g := g.next END; RETURN g END ThisDir; Syntax10.Scn.Fnt VAR f: File; i: INTEGER; BEGIN FOR i := 1 TO indent DO Out.String(" ") END; Out.String("--- "); PrintString(d.spec.name); Out.Ln; f := d.files; WHILE f # NIL DO FOR i := 1 TO indent DO Out.String(" ") END; Out.String(" "); PrintString(f.spec.name); Out.Ln; f := f.next END; f := d.dirs; WHILE f # NIL DO PrintDir(f(Directory), indent + 1); f := f.next END END PrintDir; Syntax10.Scn.Fnt VAR f: File; d1: Directory; par: FileInfo; res, n, i: INTEGER; spec: Sys.FSSpec; s: Sys.Str255; BEGIN n := 1; Out.Char("."); NEW(par); par.ioCompletion := 0; par.ioVRefNum := d.spec.vRefNum; LOOP s[0] := 0X; par.ioNamePtr := SYSTEM.ADR(s); par.ioDirID := d.dirID; par.ioFDirIndex := n; INC(n); res := Sys.PBGetCatInfo(par); IF res = 0 THEN res := Sys.FSMakeFSSpec(d.spec.vRefNum, d.dirID, s, spec); ASSERT(res = 0); IF ODD(par.ioFlAttrib DIV 16) THEN (*directory*) d1 := NewDir(spec); d1.next := d.dirs; d.dirs := d1 ELSE (*file*) f := NewFile(spec, par); f.next := d.files; d.files := f END ELSIF res = fnfErr THEN EXIT ELSE HALT(20) END END; f := d.dirs; WHILE f # NIL DO FillDir(f(Directory)); f := f.next END END FillDir; Syntax10.Scn.Fnt VAR f, g: File; first: BOOLEAN; BEGIN f := df.files; first := TRUE; WHILE f # NIL DO g := ThisFile(dt, f); IF (g = NIL) OR (f.date > g.date) THEN IF first THEN Out.String("-- "); PrintString(df.spec.name); Out.Ln; first := FALSE END; SaveFile(f, g, dt) END; f := f.next END; f := df.dirs; WHILE f # NIL DO g := ThisDir(dt, f); IF g = NIL THEN CreateDir(f(Directory), dt, g) END; SaveDir(f(Directory), g(Directory)); f := f.next END SaveDir; Syntax10b.Scn.Fnt Syntax10.Scn.Fnt VAR path: Sys.Str255; df, dt: Directory; res: INTEGER; spec: Sys.FSSpec; BEGIN In.Open; Out.Open; savedFiles := 0; LOOP ReadString(path); IF (path[0] = 0X) OR (path[1] = "~") THEN EXIT END; res := Sys.FSMakeFSSpec(0, 0, path, spec); IF res # 0 THEN Out.F("-- Invalid source directory. res = #$", res); EXIT END; df := NewDir(spec); ReadString(path); res := Sys.FSMakeFSSpec(0, 0, path, spec); IF res # 0 THEN Out.F("-- Invalid destination directory. res = #$", res); EXIT END; dt := NewDir(spec); maxLen := 0; Out.String("Reading directories"); FillDir(df); FillDir(dt); Out.Ln; NEW(buf, maxLen); (*PrintDir(df, 0); PrintDir(dt, 0);*) SaveDir(df, dt) END; Out.F("$# files saved$", savedFiles); Out.Close; buf := NIL END WriteFiles; Documentation MODULE Backup; (* HM IMPORT Sys, In, Out, SYSTEM; CONST fnfErr = -43; File = POINTER TO FileDesc; FileDesc = RECORD next: File; spec: Sys.FSSpec; date, len, rlen, creator, type: LONGINT END; Directory = POINTER TO DirectoryDesc; DirectoryDesc = RECORD (FileDesc) dirID: LONGINT; files: File; (*the files in this directory*) dirs: File (*the subdirectories in this directory*) END; DirInfo = POINTER TO DirInfoDesc; DirInfoDesc = RECORD (Sys.CInfoPBRec) ioDrUsrWds: Sys.DInfo; ioDrDirID: LONGINT; ioDrNmFls: INTEGER; f3: ARRAY 9 OF INTEGER; ioDrCrDat: LONGINT; ioDrMdDat: LONGINT; ioDrBkDat: LONGINT; ioDrFndrInfo: Sys.DXInfo; ioDrParID: LONGINT END; FileInfo = Sys.CInfoPBFilePtr; maxLen: LONGINT; (*max. file length (determines buffer sizes)*) buf: POINTER TO ARRAY OF CHAR; (*files are copied via this buffer*) savedFiles: LONGINT; (*number of saved files*) PBGetCatInfo: PROCEDURE (parm: Sys.ParmBlkPtr): INTEGER; (*--- toolbox*) PROCEDURE MakeStr255 (VAR in: ARRAY OF CHAR; VAR out: Sys.Str255); PROCEDURE GetFileInfo (spec: Sys.FSSpec; VAR par: FileInfo); PROCEDURE GetDirInfo (spec: Sys.FSSpec; VAR par: DirInfo); (*--- auxiliaries*) PROCEDURE ReadString (VAR s: ARRAY OF CHAR); PROCEDURE PrintString (s: ARRAY OF CHAR); PROCEDURE EqualString (a, b: ARRAY OF CHAR): BOOLEAN; (*--- files*) PROCEDURE NewFile (spec: Sys.FSSpec; info: FileInfo): File; PROCEDURE ThisFile (d: Directory; f: File): File; PROCEDURE SaveFile (f, g: File; dt: Directory); (*--- directories*) PROCEDURE NewDir (spec: Sys.FSSpec): Directory; PROCEDURE CreateDir (df, parent: Directory; VAR dt: File); PROCEDURE ThisDir (d: Directory; f: File): File; PROCEDURE PrintDir (d: Directory; indent: INTEGER); PROCEDURE FillDir (d: Directory); PROCEDURE SaveDir (df, dt: Directory); PROCEDURE WriteFiles*; BEGIN Sys.Assign("PBGetCatInfoSync", SYSTEM.ADR(PBGetCatInfo)); END Backup. Backup.WriteFiles Othello:Text:Vorlesungen:PI2: hm:Backup:PI2: ~ Backup.WriteFiles "Othello:Text:Vorlesungen:EiP:" hm:Backup:EiP: ~ Backup.WriteFiles Othello:AA: hm:Backup: ~ System.Free Backup~